<?php
/**
 * Smart Library - Smart Framework
 * http://smart-framework.highet.eu
 *
 * @category   SmartL
 * @package    SmartL_Zend
 * @subpackage Controller
 * @copyright  Copyright (c) 2005-2008 Smart Framework team - Stepan Sindelar, Vojtech Vit
 * @license    http://www.opensource.org/licenses/bsd-license.php	New BSD License
 */

/**
 * @see SmartL_Zend_Controller_Router_Rewrite
 */
require_once 'SmartL/Zend/Controller/Router/Rewrite.php';

/**
 * Router that looks for given url in "url-table" which is simple data table
 * with columns "url", "controllerName", "actionName", "parameters", if url is not found there
 * then the SmartL_Zend_Controller_Router_Rewrite::route is called.
 *
 * The table contains information about which url should be
 * translated to which request. One row in it is the same as static route,
 * but usage of the url-table is faster.
 *
 * The tier between this router and data is SmartL_Zend_Controller_Router_UrlTable_DataAdapter_Interface.
 * This interface provides methods for finding urls and requests and also
 * methods for adding/removing them.
 *
 * @package SmartL_Zend
 * @subpackage Controller
 */
class SmartL_Zend_Controller_Router_UrlTable extends SmartL_Zend_Controller_Router_Rewrite {
	/**
	 * @var SmartL_Zend_Controller_Router_UrlTable_DataAdapter_Interface
	 */
	protected $_dataAdapter;
	/**
	 * @var Zend_Loader_PluginLoader
	 */
	private $_loader = null;
	
	/**
	 * Returns actual data adapter.
	 *
	 * @return SmartL_Zend_Controller_Router_UrlTable_DataAdapter_Interface
	 */
	public function getDataAdapter() {
		return $this->_dataAdapter;
	}
	
	/**
	 * Returns loader configured for loading standart
	 * SmartL_Zend_Controller_Router_UrlTable_DataAdapter_* classes.
	 *
	 * @return Zend_Loader_PluginLoader
	 */
	public function getLoader() {
		if (! isset ( $this->_loader )) {
			$this->_loader = new Zend_Loader_PluginLoader ( );
			$this->_loader->addPrefixPath ( 'SmartL_Zend_Controller_Router_UrlTable_DataAdapter', 'SmartL' . DIRECTORY_SEPARATOR . 'Zend' . DIRECTORY_SEPARATOR . 'Controller' . DIRECTORY_SEPARATOR . 'Router' . DIRECTORY_SEPARATOR . 'UrlTable' . DIRECTORY_SEPARATOR . 'DataAdapter' );
		}
		
		return $this->_loader;
	}
	
	/**
	 * Use this method for inserting own loader configured to load third party data adapters.
	 *
	 * @param Zend_Loader_PluginLoader $loader
	 */
	public function setLoader(Zend_Loader_PluginLoader $loader) {
		$this->_loader = $loader;
	}
	
	/**
	 * Constructs the router.
	 *
	 * Usage of config:
	 * 		under index 'adapter' may be name of data adapter or instance of adapter itself.
	 * 		under index 'adapterConfig' may be configuration for adapter.
	 * 				This makes sence only when adapter is set as a name not as instance.
	 *
	 * @param array $config
	 */
	public function __construct(array $config = array()) {
		if (isset ( $config ['adapter'] )) {
			if (is_string ( $config ['adapter'] )) {
				$className = $this->getLoader ()->load ( ucfirst ( $config ['adapter'] ) );
				$adapterConf = isset ( $config ['adapterConfig'] ) ? $config ['adapterConfig'] : array ();
				$this->_dataAdapter = new $className ( $adapterConf );
			} elseif ($config ['adapter'] instanceof SmartL_Zend_Controller_Router_UrlTable_DataAdapter_Interface) {
				$this->_dataAdapter = $config ['adapter'];
			} else {
				require_once 'SmartL/Zend/Controller/Router/UrlTable/Exception.php';
				throw new SmartL_Zend_Controller_Router_UrlTable_Exception ( "Data adapter for UrlTable router " . "must be instance of SmartL_Zend_Controller_Router_UrlTable_DataAdapter_Interface" );
			}
		}
	}
	
	/**
	 * Find a matching route to the current PATH_INFO and inject
	 * returning values to the Request object.
	 *
	 * @param Zend_Controller_Request_Abstract $request
	 * @param SmartL_Application Application singleton, only for testing purposes.
	 * @return Zend_Controller_Request_Abstract Request object
	 */
	public function route(Zend_Controller_Request_Abstract $request, SmartL_Application $application = null) {
		if (! isset ( $this->_dataAdapter ))
			return parent::route ( $request, $application );
		
		$pathInfo = $request->getPathInfo ();
		//additional functionality
		if ($this->_dataAdapter->urlExists ( $pathInfo )) {
			$requestInfo = $this->_dataAdapter->getRequest ( $pathInfo );
			
			$request->setControllerName ( $requestInfo->getController () );
			$request->setActionName ( $requestInfo->getAction () );
			$request->setParams ( $requestInfo->getParams () );
			
			return $request;
		}
		
		//parent also checks if url is lowwercase
		$request = parent::route ( $request, $application );
		
		//no duplicity
		if ($this->_dataAdapter->requestExists ( $request->getControllerName (), $request->getActionName (), $request->getParams () )) {
			require_once 'SmartL/Zend/Controller/Router/UrlTable/Exception.php';
			throw new SmartL_Zend_Controller_Router_UrlTable_Exception ( "Duplicite url" );
		}
		
		//result
		return $request;
	}
}